package com.wlwx.simulator.handle;

import com.wlwx.simulator.codec.CMPPCommand;
import com.wlwx.simulator.message.basic.BaseMessage;
import com.wlwx.simulator.message.inbound.DeliverInBoundResponse;
import com.wlwx.simulator.message.inbound.HearthInBoundRequest;
import com.wlwx.simulator.message.inbound.LoginInBoundRequest;
import com.wlwx.simulator.message.inbound.SubmitInBoundRequest;
import com.wlwx.simulator.message.outbound.HearthOutBoundResponse;
import com.wlwx.simulator.message.outbound.LoginOutBoundResponse;
import com.wlwx.simulator.message.outbound.LogoutOutBoundResponse;
import com.wlwx.simulator.message.outbound.SubmitOutBoundResponse;
import com.wlwx.simulator.util.Cache;
import com.wlwx.simulator.util.GenerateIdUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

import static com.wlwx.simulator.codec.CMPPCommand.*;
import static com.wlwx.simulator.codec.CMPPCommand.CMPP_HEART_REQ_COMMAND;

public class CMPP20ServerHandle extends SimpleChannelInboundHandler<BaseMessage> {

    public static final AttributeKey<Integer> CMPP_LOGIN_SOURCE_ADDR_KEY = AttributeKey.valueOf("cmpp.login.source.addr");

    private static Cache CACHE = Cache.get();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BaseMessage msg) throws Exception {
        processMessageReceive(ctx, msg);
    }

    private void processMessageReceive(ChannelHandlerContext ctx, BaseMessage msg) {
        if(msg != null) {
            CMPPCommand cmppCommand ;
            switch (msg.getCode()) {
                case CMPP_LOGIN_REQ_COMMAND:
                    LoginInBoundRequest loginRequest = (LoginInBoundRequest) msg;

                    // sourceAddr 添加到channel的上下文中
                    Attribute<Integer> sourceAddrAttr = ctx.channel().attr(CMPP_LOGIN_SOURCE_ADDR_KEY);
                    Integer sourceAddr = sourceAddrAttr.get();
                    if(sourceAddr == null) {
                        sourceAddr = Integer.parseInt(loginRequest.getSourceAddr());
                        sourceAddrAttr.setIfAbsent(sourceAddr);
                    } else {
                        System.out.println("attributeMap 中是有值的, 值为 ：" + sourceAddr);
                    }

                    cmppCommand = CMPPCommand.createCommand(getLoginResp(loginRequest.getSequenceId()));
                    ctx.write(cmppCommand);
                    break;

                case CMPP_LOGOUT_REQ_COMMAND:
                    LoginInBoundRequest loginInBoundRequest = (LoginInBoundRequest) msg;
                    cmppCommand = CMPPCommand.createCommand(getLogoutResp(loginInBoundRequest.getSequenceId()));
                    ctx.write(cmppCommand);
                    ctx.close();
                    break;

                case CMPP_SUBMIT_REQ_COMMAND:
                    SubmitInBoundRequest submitRequest = (SubmitInBoundRequest) msg;

                    Attribute<Integer> sourceAddrAttr1 = ctx.channel().attr(CMPP_LOGIN_SOURCE_ADDR_KEY);
                    Integer sourceAddr1 = sourceAddrAttr1.get();

                    SubmitOutBoundResponse submitOutBoundResponse = getSubmitResp(sourceAddr1, submitRequest.getSequenceId());
                    cmppCommand = CMPPCommand.createCommand(submitOutBoundResponse);
                    System.out.println(submitOutBoundResponse);
                    ctx.write(cmppCommand);

                    // 从SUBMIT_RESP中得到msgid 并更新到SUBMIT_REQ中，然后添加到CACHE中，后面线程用于生成状态报告
                    submitRequest.setMsgId(submitOutBoundResponse.getMsgId());

                    // 要求返回状态确认报告
                    if(submitRequest.getRegisteredDelivery() == 1)  {
                        if(!CACHE.addSubmitRequest(ctx, submitRequest)) {
                            System.out.println("CMPP_SUBMIT_REQ_COMMAND : " + submitRequest+
                                    " add SubmitRequest to cache failed!");
                        }
                    }

                    break;

                case CMPP_DELIVER_RESP_COMMAND :
                    DeliverInBoundResponse response = (DeliverInBoundResponse) msg;
                    // 重发状态报告时候 可以写额外的逻辑
                    break;

                case CMPP_HEART_REQ_COMMAND:
                    HearthInBoundRequest hearthRequest = (HearthInBoundRequest) msg;
                    cmppCommand = CMPPCommand.createCommand(getHearthResp(hearthRequest.getSequenceId()));
                    ctx.write(cmppCommand);

                    break;

                default:
                    break;
            }

            ctx.flush();
        }
    }

    private LoginOutBoundResponse getLoginResp(int sequenceId) {
        LoginOutBoundResponse response = new LoginOutBoundResponse(sequenceId);
        response.setStatus((byte) 0X00);
        response.setAuthenticatorISMG(String.format("%16d",0));
        response.setVersion((byte) 0X20);
        return response;
    }

    private LogoutOutBoundResponse getLogoutResp(int sequenceId) {
        LogoutOutBoundResponse response = new LogoutOutBoundResponse(sequenceId);
        return response;
    }


    private HearthOutBoundResponse getHearthResp(int sequenceId) {
        HearthOutBoundResponse response = new HearthOutBoundResponse(sequenceId);
        return response;
    }

    private SubmitOutBoundResponse getSubmitResp(int sourceAddr, int sequenceId) {
        SubmitOutBoundResponse submitResponse = new SubmitOutBoundResponse(sequenceId);
        submitResponse.setMsgId(GenerateIdUtil.generateMsgId(sourceAddr));
        submitResponse.setResult((byte) 0x00);
        return submitResponse;
    }
}
